package com.lf.freezingpoint.common.security.manager;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.access.intercept.RequestAuthorizationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
import java.util.logging.Logger;

/**
 * 自定义JWT鉴权管理器
 * 根据请求路径匹配用户角色鉴权
 */
@Component
public class JWTAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
    private static final Logger logger = Logger.getLogger(JWTAuthorizationManager.class.toString());

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext requestAuthorizationContext) {
        HttpServletRequest request = requestAuthorizationContext.getRequest();

        String method = request.getMethod();
        String uri = request.getRequestURI();
        String restfulPath = method + ":" + uri;
        logger.info("待鉴定权限:" + restfulPath);

        List<String> authorizedRoles; // 拥有访问权限的角色,通过请求路径获取所需角色,实际从redis中比对返回
        authorizedRoles = (List<String>) redisTemplate.opsForValue().get(restfulPath);

        boolean isGranted;
        Collection<? extends GrantedAuthority> authorities = authentication.get().getAuthorities();
        for (GrantedAuthority authority : authorities) {
            String role = authority.getAuthority().replace("ROLE_", "");
            if ("admin".equals(role)) {
                logger.info("鉴定结果:" + true);
                return new AuthorizationDecision(true);
            }
            isGranted = !CollectionUtils.isEmpty(authorizedRoles) && authorizedRoles.contains(role);
            if (isGranted) {
                logger.info("鉴定结果:" + true);
                return new AuthorizationDecision(true);
            }
        }
        logger.info("鉴定结果:" + false);
        return new AuthorizationDecision(false);
    }
}
